﻿using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using MyServer.Common.Tools;
using System.Collections;
using FrameWork.Log;
using FrameWork.Setting;
using System.ComponentModel;

namespace MyServer.Common
{
    /// <summary>
    /// 为读取超时事件提供数据存储
    /// </summary>
    public sealed class ReadTimeoutEventArgs:CancelEventArgs
    {
        /// <summary>
        /// 表示读取超时的数据包
        /// </summary>
        public DataPackageCollection TimeoutPkg { get; set; }
    }
    /// <summary>
    /// 表示数据读取器基类
    /// </summary>
    [SettingParentDefine]
    public abstract class DataReaderBase : QueueOperateItemBase
    {

        #region ==========属性==========

        /// <summary>
        /// 获取当前已读取但未能分组的数据包列表
        /// </summary>
        protected ArrayList UnGroupedPkg { get; set; }

        /// <summary>
        /// 表示与读取器绑定的数据中心
        /// </summary>
        public DataCenterBase DataCenter { get; private set; }

        /// <summary>
        /// 获取正在接收的客户端信息列表
        /// 类型：<see cref="MyServer.Common.RecivingConnectInfo"/>
        /// </summary>
        protected ArrayList RecivingConnectList { get; set; }

        /// <summary>
        /// 获取数据读取器使用的压缩器
        /// </summary>
        public DataCompressorBase Compressor { get;private set; }

        /// <summary>
        /// 获取或设置读取器的超时时间
        /// </summary>
        [SettingItemDefine(SettingValueType.Int32,10000)]
        [Browsable(true)]
        [Category("常规")]
        [DisplayName("超时时间")]
        [Description("表示数据读取器的超时时间")]
        public int ReadTimeOutValue { get; set; }

        #endregion

        #region==========事件==========
        /// <summary>
        /// 当读取器读取超时是执行的事件
        /// </summary>
        public event EventHandler<ReadTimeoutEventArgs> ReadTimeout;
        #endregion

        #region ========私有函数========

        /// <summary>
        /// 加入链接
        /// </summary>
        /// <param name="tag"></param>
        private void AddConnect(object tag)
        {
            lock (RecivingConnectList)
            {
                foreach (RecivingConnectInfo i in RecivingConnectList.ToArray())
                {
                    if (i.Tag == tag)
                    {
                        i.RecivingCount++;
                        return;
                    }
                }
                RecivingConnectInfo info = new RecivingConnectInfo(tag);
                RecivingConnectList.Add(info);
            }
        }

        /// <summary>
        /// 移除链接
        /// </summary>
        /// <param name="tag"></param>
        private void RemoveConnect(object tag)
        {
            lock (RecivingConnectList)
            {
                foreach (RecivingConnectInfo i in RecivingConnectList.ToArray())
                {
                    if (i.Tag == tag)
                    {
                        if (i.RecivingCount == 1)
                        {
                            RecivingConnectList.Remove(i);
                        }
                        else
                        {
                            i.RecivingCount--;
                        }
                        return;
                    }
                }
            }
        }

        #endregion

        #region========公用方法========

        /// <summary>
        /// 获取拥有指定Tag数据的数据包的剩余数量
        /// </summary>
        /// <param name="tag"></param>
        /// <returns>若没有数据则返回-1,否则返回数量</returns>
        public virtual int GetTagLeftPacket(object tag)
        {
            lock (RecivingConnectList)
            {
                foreach (RecivingConnectInfo i in RecivingConnectList.ToArray())
                {
                    if (i.Tag == tag)
                    {
                        return i.RecivingCount;
                    }
                }
                return -1;
            }
        }
        /// <summary>
        /// 获取读取其中未分组的数据包数量
        /// </summary>
        /// <returns></returns>
        public virtual int GetUnGroupPkgCount()
        {
            return UnGroupedPkg.Count;
        }

        #endregion

        #region=========虚函数=========
        /// <summary>
        /// 开始尝试读取指定包中的数据
        /// </summary>
        /// <param name="pkg">要读取的数据包列表</param>
        /// <returns>是否成功完成一次操作</returns>
        protected virtual OperateResult Read(ref DataPackageCollection pkg)
        {
            try
            {
                if (pkg.State == PackageCollectionState.ReciveCompelete)
                    return OperateResult.Success;
                if (GetDataAvilable(pkg.Tag) <= 0)
                {
                    if (ReadTimeOutValue!=-1 && Environment.TickCount - pkg.LastAddDataTick >= ReadTimeOutValue)
                    {
                        if (ReadTimeout != null)
                        {
                            ReadTimeoutEventArgs e = new ReadTimeoutEventArgs();
                            e.TimeoutPkg = pkg;
                            ReadTimeout(this, e);
                            if(e.Cancel)
                                return OperateResult.Fail;
                        }
                        else
                        {
                            return OperateResult.Fail;
                        }
                    }
                    pkg.State = PackageCollectionState.Reciving;
                    return OperateResult.Ignore;
                }
                //取得数据包内包含的流信息
                Stream stream = GetStream(pkg.Tag);
                BinaryReader br = new BinaryReader(stream);

                bool ispkgcol = br.ReadBoolean();//读取当前数据块是否为新的数据包列表

                int dataLen = br.ReadInt32();//取得数据长度

                byte[] dataBuffer = br.ReadBytes(dataLen);

                if(Compressor!=null)
                {
                    dataBuffer = Compressor.DeCompress(dataBuffer);
                }

                if (!ispkgcol)//数据类型为数据包
                {
                    DataPackage rpkg = DataPackage.FromByte(dataBuffer);

                    if (rpkg.PackageName != pkg.PackageName)//当前接收的数据包不属于当前数据包集合
                    {
                        pkg.State = PackageCollectionState.Reciving;
                        rpkg.Tag = pkg.Tag;//将当前连接绑定到数据包
                        UnGroupedPkg.Add(rpkg);//将数据包加入至未分组数据包列表中
                        return OperateResult.Success;
                    }
                    else//当前接收的数据包属于当前数据包集合
                    {
                        pkg.Add(rpkg);//将数据包加入数据包集合中
                        pkg.OperatedPkgCount++;
                        if (pkg.OperatedPkgCount == pkg.Count)
                            pkg.State = PackageCollectionState.ReciveCompelete;
                        return OperateResult.Success;
                    }
                }
                else//数据类型为数据包列表
                {

                    DataPackageCollection npkg;

                    if (pkg.State == PackageCollectionState.Created)
                    {
                        npkg = pkg;
                    }
                    else
                    {
                        npkg = new DataPackageCollection("", PackageCollectionType.ForRecive);
                        npkg.Tag = pkg.Tag;
                        pkg.State = PackageCollectionState.Reciving;
                    }

                    npkg.InitFromByte(dataBuffer);//读取数据包列表

                    if (npkg.State != PackageCollectionState.Inited)
                        return OperateResult.Fail;
                    if (npkg.DataCount == 0)
                    {
                        npkg.State = PackageCollectionState.ReadyForRecive;
                    }
                    else
                    {
                        npkg.State = PackageCollectionState.ReciveCompelete;
                        return OperateResult.Success;
                    }
                    bool isExist = false;

                    lock (OperateQueue)
                    {
                        foreach (DataPackageCollection p in OperateQueue.ToArray())
                        {
                            if (p.PackageName == npkg.PackageName)//数据包列表已存在在队列中
                            {
                                //清除数据包列表中的数据包，准备重新接收数据包
                                p.Clear();
                                p.OperatedPkgCount = 0;
                                p.State = PackageCollectionState.Reciving;
                                isExist = true;
                                break;
                            }
                        }
                        if (!isExist)//当数据包列表不在队列中时
                        {
                            OperateQueue.Enqueue(npkg);//将数据包列表加入接收队列中
                            AddConnect(npkg.Tag);
                        }
                    }
                    return OperateResult.Success;
                }
            }
            catch
            {
#if DEBUG
                throw;
#else
                return OperateResult.Fail;
#endif
            }
        }
        #endregion

        #region========抽象函数========

        /// <summary>
        /// 根据数据包的Tag标签获取读取数据包的流
        /// </summary>
        /// <param name="Tag">Tag标签</param>
        /// <returns>获取到的流</returns>
        protected abstract Stream GetStream(object Tag);
        /// <summary>
        /// 获取数据包Tag流中可供读取的数据数
        /// </summary>
        /// <param name="Tag"></param>
        /// <returns></returns>
        protected abstract int GetDataAvilable(object Tag);
        /// <summary>
        /// 检查指定客户端是否相同
        /// </summary>
        /// <param name="Left"></param>
        /// <param name="Right"></param>
        /// <returns></returns>
        protected abstract bool CheckClient(object Left, object Right);
        #endregion

        #region========构造函数========
        /// <summary>
        /// 构造数据读取器实例
        /// </summary>
        /// <param name="Center">与数据读取器绑定的数据中心</param>
        /// <param name="Compressor">与数据读取器绑定的数据压缩器</param>
        public DataReaderBase(DataCenterBase Center,DataCompressorBase Compressor=null)
        {

            this.UnGroupedPkg = ArrayList.Synchronized(new ArrayList());
            this.RecivingConnectList = ArrayList.Synchronized(new ArrayList());

            //初始化设定
            this.DataCenter = Center;
            this.Compressor = Compressor;
        }

        #endregion

        #region========基类实现========

        protected override OperateResult DoOperateSetp(DataPackageCollection pkg, out DataPackageCollection repkg)
        {
            pkg.IsRecive = true;
            RemoveConnect(pkg.Tag);
            repkg = null;
            return Read(ref pkg);
        }

        protected override bool BeforeOperateSetp(DataPackageCollection pkg)
        {
            //校验未分组的数据包
            lock (UnGroupedPkg)
            {
                foreach (DataPackage ugppkg in UnGroupedPkg.ToArray())
                {
                    if (CheckClient(ugppkg.Tag,pkg.Tag) && ugppkg.PackageName == pkg.PackageName)
                    {
                        pkg.Add(ugppkg);
                        pkg.OperatedPkgCount++;
                        UnGroupedPkg.Remove(ugppkg);
                        if (pkg.OperatedPkgCount == pkg.Count)
                        {
                            pkg.State = PackageCollectionState.ReciveCompelete;
                            return true;
                        }
                    }
                }
                return true;
            }
        }

        protected override bool AfterOperateSetp(DataPackageCollection pkg)
        {
            //终结点判定
            if ((pkg.OperatedPkgCount < pkg.Count && pkg.State == PackageCollectionState.Reciving))//正在处理
            {
                AddConnect(pkg.Tag);
                return true;
            }
            if (pkg.State == PackageCollectionState.ReadyForRecive)//准备接收
            {
                pkg.State = PackageCollectionState.Reciving;
            }
            else if (pkg.OperatedPkgCount == pkg.Count)//接收完毕
            {
                pkg.State = PackageCollectionState.ReciveCompelete;
            }
            else if (pkg.OperatedPkgCount > pkg.Count)//接收不规范
            {
                PrintLog(LogType.Waring, "数据包接受不规范！已移除！", pkg);
                pkg.State = PackageCollectionState.ErrorRead;
            }
            return false;
        }

        #endregion

    }

}
